package parDef

import (
	"context"
	"fmt"
	"db2s/ETL"
	"db2s/global"
	"strings"
)

type (
	Return struct {
		Sql          string
		TimeOut      int64
		InsideResult any
		Result       any
	}
)

type FuncParameterKey string

var (
	SchemaParameterValue                   FuncParameterKey = "schema"
	TableParameterValue                    FuncParameterKey = "table"
	PartitionParameterValue                FuncParameterKey = "partition"
	TableColumnMapParameterValue           FuncParameterKey = "tableColumnMap"
	TableIndexColumnMapParameterValue      FuncParameterKey = "tableIndexColumnMap"
	TableLockColumnFuncParameterValue      FuncParameterKey = "tableLockColumnFunc"
	RecoverSchemaParameterValue            FuncParameterKey = "recoverSchema"
	RecoverTableParameterValue             FuncParameterKey = "recoverTable"
	TablePositParameterValue               FuncParameterKey = "posit"
	TableParallelQueryParameterValue       FuncParameterKey = "tablePositQuery"
	TableWhereSqlParameterValue            FuncParameterKey = "whereSql"
	TableWhereAddParameterValue            FuncParameterKey = "whereAdd"
	TableLimitParameterValue               FuncParameterKey = "limit"
	IndexColumnNameParameterValue          FuncParameterKey = "indexColumnName"
	TruncateObjectParameterValue           FuncParameterKey = "truncateObject"
	GeneralAlterRuleParameterValue         FuncParameterKey = "generalAlterRule"
	MetaParameterValue                     FuncParameterKey = "meta"
	DDLSqlParameterValue                   FuncParameterKey = "ddlSql"
	DMLSqlParameterValue                   FuncParameterKey = "dmlSql"
	DDLSqlFilePointParameterValue          FuncParameterKey = "ddlSqlFilePoint"
	DMLSqlFilePointParameterValue          FuncParameterKey = "dmlSqlFilePoint"
	ExpectParameterValue                   FuncParameterKey = "expect"
	ExecSqlFuncParameterValue              FuncParameterKey = "execSqlFunc"
	RepairMethodParameterValue             FuncParameterKey = "repairMethod"
	DbReadOptionsParameterValue            FuncParameterKey = "dbReadOptions"
	DbWriteOptionsParameterValue           FuncParameterKey = "dbWriteOptions"
	ExternalExecFuncParameterValue         FuncParameterKey = "externalExecFunc"
	ExternalGetJsonValueFuncParameterValue FuncParameterKey = "externalGetJsonValueFunc"
	LobTableLogoParameterValue             FuncParameterKey = "lobTableLogo"
	GeneralInsertSqlParameterValue         FuncParameterKey = "generalInsertSql"
)

func GetSchemaParameterValue() FuncParameterKey {
	return SchemaParameterValue
}
func GetTableParameterValue() FuncParameterKey {
	return TableParameterValue
}
func GetPartitionParameterValue() FuncParameterKey {
	return PartitionParameterValue
}
func GetTableColumnMapParameterValue() FuncParameterKey {
	return TableColumnMapParameterValue
}
func GetTableLockColumnFuncParameterValue() FuncParameterKey {
	return TableLockColumnFuncParameterValue
}
func GetTableIndexColumnMapParameterValue() FuncParameterKey {
	return TableIndexColumnMapParameterValue
}
func GetTablePositParameterValue() FuncParameterKey {
	return TablePositParameterValue
}
func GetTableParallelQueryParameterValue() FuncParameterKey {
	return TableParallelQueryParameterValue
}
func GetTableWhereSqlParameterValue() FuncParameterKey {
	return TableWhereSqlParameterValue
}
func GetTableWhereAddParameterValue() FuncParameterKey {
	return TableWhereAddParameterValue
}
func GetTableLimitParameterValue() FuncParameterKey {
	return TableLimitParameterValue
}
func GetIndexColumnNameParameterValue() FuncParameterKey {
	return IndexColumnNameParameterValue
}
func GetRecoverSchemaParameterValue() FuncParameterKey {
	return RecoverSchemaParameterValue
}
func GetRecoverTableParameterValue() FuncParameterKey {
	return RecoverTableParameterValue
}
func GetTruncateObjectParameterValue() FuncParameterKey {
	return TruncateObjectParameterValue
}
func GetLobTableLogoParameterValue() FuncParameterKey {
	return LobTableLogoParameterValue
}

func GetGeneralAlterRuleParameterValue() FuncParameterKey {
	return GeneralAlterRuleParameterValue
}
func GetMetaParameterValue() FuncParameterKey {
	return MetaParameterValue
}
func GetGeneralInsertSqlParameterValue() FuncParameterKey {
	return GeneralInsertSqlParameterValue
}
func GetDDLSqlFilePointParameterValue() FuncParameterKey {
	return DDLSqlFilePointParameterValue
}
func GetDMLSqlFilePointParameterValue() FuncParameterKey {
	return DMLSqlFilePointParameterValue
}
func GetDDLSqlParameterValue() FuncParameterKey {
	return DDLSqlParameterValue
}
func GetDMLSqlParameterValue() FuncParameterKey {
	return DMLSqlParameterValue
}
func GetExpectParameterValue() FuncParameterKey {
	return ExpectParameterValue
}
func GetExecSqlFuncParameterValue() FuncParameterKey {
	return ExecSqlFuncParameterValue
}
func GetRepairMethodParameterValue() FuncParameterKey {
	return RepairMethodParameterValue
}
func GetDbReadOptionsParameterValue() FuncParameterKey {
	return DbReadOptionsParameterValue
}

func GetDbWriteOptionsParameterValue() FuncParameterKey {
	return DbWriteOptionsParameterValue
}
func GetExternalExecFuncParameterValue() FuncParameterKey {
	return ExternalExecFuncParameterValue
}
func GetExternalGetJsonValueFuncParameterValue() FuncParameterKey {
	return ExternalGetJsonValueFuncParameterValue
}
func GetFuncParameterValue(ctx context.Context, key FuncParameterKey) any {
	switch data := ctx.Value("key"); data.(type) {
	case Parameter:
		switch key {
		case SchemaParameterValue:
			return data.(Parameter).Object.Schema
		case RecoverSchemaParameterValue:
			return data.(Parameter).Object.RecoverSchema
		case RecoverTableParameterValue:
			return data.(Parameter).Object.RecoverTable
		case TableParameterValue:
			return data.(Parameter).Object.Table
		case IndexColumnNameParameterValue:
			return data.(Parameter).Object.IndexCol
		case TableColumnMapParameterValue:
			return data.(Parameter).Object.Column
		case TableIndexColumnMapParameterValue:
			return data.(Parameter).Object.Index.ColumnMate
		case TableLockColumnFuncParameterValue:
			return data.(Parameter).Object.LockCol
		case TableParallelQueryParameterValue:
			return data.(Parameter).Options.TablePx
		case PartitionParameterValue:
			return data.(Parameter).Object.Partition
		case TruncateObjectParameterValue:
			return data.(Parameter).Object.TruncatePartition
		case TablePositParameterValue:
			return data.(Parameter).Options.Scn
		case TableWhereSqlParameterValue:
			return data.(Parameter).Options.WhereSql
		case TableWhereAddParameterValue:
			return data.(Parameter).Options.WhereAdd
		case TableLimitParameterValue:
			return data.(Parameter).Options.RowsLimit
		case LobTableLogoParameterValue:
			return data.(Parameter).Object.LobLogo
		case MetaParameterValue:
			return data.(Parameter).Meta
		case GeneralAlterRuleParameterValue:
			return data.(Parameter).Options.AlterDDL.Rule
		case DDLSqlParameterValue:
			return data.(Parameter).ExecDDL.Sql
		case DMLSqlParameterValue:
			return data.(Parameter).ExecDML.Sql
		case DDLSqlFilePointParameterValue:
			return data.(Parameter).ExecDDL.FilePoint
		case DMLSqlFilePointParameterValue:
			return data.(Parameter).ExecDML.FilePoint
		case ExpectParameterValue:
			return data.(Parameter).Options.Expect
		case ExecSqlFuncParameterValue:
			return data.(Parameter).ExecSqlFunc
		case RepairMethodParameterValue:
			return data.(Parameter).Options.RepairMethod
		case DbReadOptionsParameterValue:
			return ETL.ReadOpt{
				DB:        data.(Parameter).Con,
				FixRows:   data.(Parameter).Options.FixRows,
				StopTime:  data.(Parameter).Options.StopTime,
				SqlMode:   data.(Parameter).Options.SqlMode,
				SqlLogBin: data.(Parameter).Options.SqlLogBin,
			}
		case DbWriteOptionsParameterValue:
			return ETL.WriteOpt{
				DB:        data.(Parameter).Con,
				FixRows:   data.(Parameter).Options.FixRows,
				StopTime:  data.(Parameter).Options.StopTime,
				SqlMode:   data.(Parameter).Options.SqlMode,
				SqlLogBin: data.(Parameter).Options.SqlLogBin,
			}
		case ExternalExecFuncParameterValue:
			return data.(Parameter).ExecFunc
		case ExternalGetJsonValueFuncParameterValue:
			return data.(Parameter).GetJsonValue
		}
		return nil
	default:
		return nil
	}
}
func SwapCtxKeyValue(ctx context.Context, key string, newValue any) (ctxNew context.Context) {
	var oldKeyValue = ctx.Value("key")
	switch oldKeyValue.(type) {
	case Parameter:
		newKey := oldKeyValue.(Parameter)
		switch key {
		case "expect":
			newKey.Options.Expect = fmt.Sprintf("%v", newValue)
		case "meta":
			newKey.Meta = newValue
		}
		ctxNew = CtxBackground(newKey)
	}
	return
}
func GetParameterValueAnyToString(s any) (r string) {
	if s == nil {
		return
	}
	return fmt.Sprintf("%v", s)
}
func GetParameterValueAnyToMapStringGarth(s any) (r []map[string]string) {
	switch s.(type) {
	case []map[string]string:
		r = s.([]map[string]string)
	}
	return
}
func GetParameterValueAnyToColMetaMapSGarth(s any) (r []ColMetaMapS) {
	switch s.(type) {
	case []ColMetaMapS:
		r = s.([]ColMetaMapS)
	}
	return
}
func GetParameterValueAnyToStringGarth(s any) (r []string) {
	return s.([]string)
}
func GetParameterValueAnyToBool(s any) (r bool) {
	return s.(bool)
}
func GetParameterValueAnyToInt(s any) (r int) {
	if s == nil {
		return
	}
	return s.(int)
}
func GetReadDbExecOptions(s any) (res ETL.ReadOpt) {
	switch s.(type) {
	case ETL.ReadOpt:
		return s.(ETL.ReadOpt)
	}
	return
}
func GetWriteDbExecOptions(s any) (res ETL.WriteOpt) {
	switch s.(type) {
	case ETL.WriteOpt:
		return s.(ETL.WriteOpt)
	}
	return
}
func GetExternalExecFunc(s any) func(s any, execFunc any) (any, error) {
	switch s.(type) {
	case func(s any, execFunc any) (any, error):
		return s.(func(s any, execFunc any) (any, error))
	}
	return nil
}
func GetExternalGetJsonValueFunc(s any) func(s any, key string) (any, error) {
	switch s.(type) {
	case func(s any, key string) (any, error):
		return s.(func(s any, key string) (any, error))
	}
	return nil
}
func GetDbExecSqlFunc(s any) func(ctx context.Context, S any, GisValFunc func(any) any, sessionOptions, sqlStr []string, expect string) (global.Return, error) {
	switch s.(type) {
	case func(ctx context.Context, S any, GisValFunc func(any) any, sessionOptions, sqlStr []string, expect string) (global.Return, error):
		return s.(func(ctx context.Context, S any, GisValFunc func(any) any, sessionOptions, sqlStr []string, expect string) (global.Return, error))
	}
	return nil
}

func CtxBackground(parameter any) (ctx context.Context) {
	ctx = context.Background()
	if parameter != nil {
		ctx = context.WithValue(ctx, "key", parameter)
		return
	}
	return
}

func GeneralReadMethodParameter(parameter Parameter, execFunc func(s any, execFunc any) (any, error), expect string) (res Parameter) {
	res = parameter
	res.ExecSqlFunc = ETL.QuerySql
	if execFunc != nil {
		res.ExecFunc = execFunc
	}
	res.Options.Expect = expect
	return
}
func GeneralWriteMethodParameter(parameter Parameter, execFunc func(s any, execFunc any) (any, error), expect string) (res Parameter) {
	res = parameter
	if execFunc != nil {
		res.ExecFunc = execFunc
	}
	res.Options.Expect = expect
	return
}
func joinExec(join string, k int) bool {
	switch {
	case strings.EqualFold(join, "left") && k == 1:
		return true
	case strings.EqualFold(join, "right") && k == 0:
		return true
	}
	return false
}
func joinResult(join string, obj []any) (res any) {
	switch join {
	case "left":
		return obj[0]
	case "right":
		if len(obj) == 1 {
			return obj[0]
		}
		return obj[1]
	case "join":
		return obj
	}
	return
}
func CallMethod(drive []string, join string, method func(k int, v string) (result global.Return, err error)) (meta any, err error) {
	var res []any
	for k, v := range drive {
		if len(drive) > 1 && joinExec(join, k) {
			res = append(res, nil)
			continue
		}
		var result global.Return
		if result, err = method(k, v); err != nil {
			return
		}
		res = append(res, result.Result)
	}
	meta = joinResult(join, res)
	return
}

func CallMethodRes(drive []string, join string, method func(k int, v string) (result global.Return, err error)) (meta any, err error) {
	var res []any
	for k, v := range drive {
		if len(drive) > 1 && joinExec(join, k) {
			res = append(res, nil)
			continue
		}
		var result global.Return
		if result, err = method(k, v); err != nil {
			return
		}
		res = append(res, result)
	}
	meta = joinResult(join, res)
	return
}
